#include "Clients.h"
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <memory.h>
#include "..\Utils\Utils.h"
#include "..\List\LIST.h"
#include "..\Properties\Properties.h"

#pragma warning (disable: 4996)

//Shows list of demands, user select the demand and index returned.
int Select_Client_Request(Client C)
{
int i,j;
char **arr;
Position PO;
DemandProperty P;

if (C.RequestCount==0)
{
	ConfirmationMessage("Client don't have any Requests."); 
	return -1;

}
PO = First(C.RequestList);

arr = (char **)malloc(C.RequestCount * (sizeof(char *)));
for (i=0;i<C.RequestCount;i++)
	{
		arr[i] = (char*)malloc(sizeof(char) * 150);
		P = Retrieve(PO);
		sprintf(arr[i],"%s, %d$, %s, %s, %d.",P.DemandRecord.DemandCity,P.DemandRecord.DemandPrice,
		DPKindStrings[P.DemandRecord.DemandKind],DPDemandTypeStrings[P.DemandRecord.DemandType],
		P.DemandRecord.DemandRooms);
		
		PO = Advance(PO);
	}

i=0;
j=0;
j = menu(arr,C.RequestCount,i,"Select Demand",10);

for (i=0;i<C.RequestCount;i++)
	free(arr[i]);
free(arr);

return j;


}
//Shows menu of demands fields, user select demand, field, and update it.
void Client_Update_Requests(Client *ClientsArray,int cid)
{
int reqid,fieldid;
reqid = Select_Client_Request(ClientsArray[cid]);

if (reqid==-1)
	return;

fieldid =  menu(DemandClientStrings,DemandClientLength,0,"Select Field : ",12);

if (fieldid==-1)
 return;

switch (fieldid)
{
case 0: Client_Update_Demands_Kind(ClientsArray,reqid,cid) ;break;
case 1: Client_Update_Demands_Type(ClientsArray,reqid,cid) ;break;
case 2: Client_Update_Demands_Price(ClientsArray,reqid,cid);break;
case 3: Client_Update_Demands_City(ClientsArray,reqid,cid) ;break;
case 4: Client_Update_Demands_Rooms(ClientsArray,reqid,cid);break;
}
}
//Update client active/disable field
void Client_Update_Active(Client *ClientsArray,int clientid)
{
	Client_Insert_Between(&ClientsArray[clientid].Active,ActiveStrings,ActiveStringsLength,"Select To Update:");
}
//Update gender - male/female field
void Client_Update_Gender(Client *ClientsArray,int clientid)
{
	Client_Insert_Between(&ClientsArray[clientid].Gender,GenderStrings,ActiveStringsLength,"Gender:");
}
//Update name
void Client_Update_Name(Client *ClientsArray,int clientid)
{
	Client_Insert_String(ClientsArray[clientid].Name,"Enter Client Name: ",20,TEXT_S);
}
//Update Phone numbe
void Client_Update_Phone(Client *ClientsArray,int clientid)
{
	Client_Insert_String(ClientsArray[clientid].Phone,"Enter Client Phone: ",20,NUM_S);
}
//Update Family name
void Client_Update_Family(Client *ClientsArray,int clientid)
{
	Client_Insert_String(ClientsArray[clientid].Family,"Enter Client Family: ",20,TEXT_S);
}
//Update City
void Client_Update_City(Client *ClientsArray,int clientid)
{
	Client_Insert_String(ClientsArray[clientid].City,"Enter Client City: ",20,TEXT_S);
}
//Update Street
void Client_Update_Street(Client *ClientsArray,int clientid)
{
	Client_Insert_String(ClientsArray[clientid].Street,"Enter Client Street: ",20,TEXT_S);
}
//Selects one client from menu, and start update his fields.
void UpdateClients(Client **ClientsArray,int *ClientCount,VoidCallBack CB)
{
int id;
if (*ClientCount==0)
	{	
		ConfirmationMessage("There are no clients in the system.");
		CB();
		return;
	}
id = SelectClientFromList(*ClientsArray,ClientCount);
if (id==-1) {CB();return;}
	Start_Update_Client(*ClientsArray,id);
CB();
}
//Selects client fields, user select field and start to update it.
void Start_Update_Client(Client *ClientsArray,int cid)
{
int field=0;

field = menu(clientfieldstrings,ClientFieldsLength,field,"Select",10);

switch (field)
{
case 0:;break;
case 1:Client_Update_Name(ClientsArray,cid);break;
case 2:Client_Update_Family(ClientsArray,cid);break;
case 3:Client_Update_Phone(ClientsArray,cid);break;
case 4:Client_Update_City(ClientsArray,cid);break;
case 5:Client_Update_Street(ClientsArray,cid);break;
case 6:Client_Update_Active(ClientsArray,cid);break;
case 7:Client_Update_Gender(ClientsArray,cid);break;
case 8:Client_Update_Requests(ClientsArray,cid);break;
}
if (field!=-1)
	ConfirmationMessage("Client Updated.");
}
//Shows list of clients, user select client,function return index in array
int SelectClientFromList(Client *ClientsArray,int *ClientCount)
{
char **arr;
int i,j;
arr = (char **)malloc((*ClientCount) * (sizeof(char *)));
for (i=0;i<*ClientCount;i++)
	{
		arr[i] = (char*)malloc(sizeof(char) * 50);
		strcpy(arr[i],ClientsArray[i].ID);
		strcat(arr[i], " , ");
		strcat(arr[i],ClientsArray[i].Name);
	}

i=0;
j=0;
j = menu(arr,*ClientCount,i,"Select",10);

for (i=0;i<*ClientCount;i++)
	free(arr[i]);
free(arr);

return j;

}
//Main page of the all clients.shows one client per page with options.
void ShowAllClients(Client **ClientsArray,int *ClientCount,VoidCallBack CB)
{
int i;
char ch;
for(i=0;i<*ClientCount;i++)
{	
	ch = ShowClient(ClientsArray,ClientCount,&(*ClientsArray)[i],i); 

	if (ch==27)
	{
		if (AskYesNoQuestion("Stop Viewing Clients ?"))
			break;
	}
	else 
	{
		if (ch==0) //update
			 i--;  // stay in place


		if (ch==1) //back
			if(i>=1) // have valid index, step back twice
				i-=2;
			else
				i--; // stay in place
			
	}
}
CB();
}
//Shows one client info in the page. pointer to the cliet = C
int ShowClient(Client **ClientsArray,int *ClientCount,Client *C,int index)
{
	int i;
	char buf[50],ch;
	
	Position PO;
	DemandProperty P;
	
	showoutputimage(0);
	ClientsOptions();	

  if (index !=-1)
  {
	sprintf(buf,"Clients(%d of %d)",index+1,*ClientCount);  

	puttext(buf,40,1,0x0c,1,0);
	fillascii(3,2,75,2,'-',0x0c);
  }
	
	puttext("ID :",10,5,0x0a,0,0);
	puttext(C->ID,20+10,5,0x0b,0,0);

	puttext("Name :",10,6,0x0a,0,0);
	puttext(C->Name,20+10,6,0x0b,0,0);

	puttext("Family :",10,7,0x0a,0,0);
	puttext(C->Family,20+10,7,0x0b,0,0);

	puttext("Phone :",10,8,0x0a,0,0);
	puttext(C->Phone,20+10,8,0x0b,0,0);

	puttext("City :",10,9,0x0a,0,0);
	puttext(C->City,20+10,9,0x0b,0,0);

	puttext("Demands",40,11,0x0c,1,0);
	fillascii(3,12,75,12,'-',0x0c);
	// if demands exist, print them in the page below the info
	if (C->RequestCount>0)
	{
		PO = First(C->RequestList);
		for(i=0;i<C->RequestCount;i++)
		{
		 P = Retrieve(PO);
		 PO = Advance(PO);
		 settextcolor(0x0d);
		 gotoxy(10,13+i);
		 printf("%d: %s, %d$, %s, %s, %d rooms. ",i+1,P.DemandRecord.DemandCity ,
		 P.DemandRecord.DemandPrice,DPKindStrings[P.DemandRecord.DemandKind],
		 DPDemandTypeStrings[P.DemandRecord.DemandType],
		 P.DemandRecord.DemandRooms);

		}
	}

	if (C->Active==1) // if disable, gray screen
		GrayScreen(112);
	else
	{
		if (C->Gender==1)
			printwoman(64,4); //print man
		else
			printman(62,4);  //print woman

	}
	
	do
	{
		ch = getch();
		if (ch=='U' || ch=='u' || ch=='d' || ch=='D' || ch=='e' || ch=='E')
		{
			i = FindClientID(*ClientsArray,ClientCount,C);
			if (i!=-1)
			{// Submenu options for reduction
				if (ch=='u' || ch=='U')
					Start_Update_Client(*ClientsArray,i);
				if (ch=='e' || ch=='E')
					Start_Delete_Client(ClientsArray,ClientCount,i);
				if (ch=='d' || ch=='D')
					Start_Edit_Demands(*ClientsArray,ClientCount,i);
				ch=0;
			}
		}
		if (ch==0,ch==75) //left
			ch=1;

		if (ch==0,ch==77) //right
			ch=13;

	}
	while (ch!=27 && ch!=13 && ch!=0 && ch!=1);

	return (int)ch;

}

//Function load and return array of clients that inside the file.update client count
Client * LoadClientsFromFile(int *ClientCount)
{
FILE *fp;
Client *ClientsArray=NULL;
Client C;
DemandProperty P;
Position PO;
int i=0;

fp = fopen(ClientsFile,"rb+");
if (fp==NULL)
{
 //printf("Error Open File...");
 //exit(1);
 return NULL;
}

while (fread(&C,sizeof(Client),1,fp)) //while file not ended
{
	if (C.RequestCount>0) //if there are any demands in this client
	{
		C.RequestList = MakeEmpty(NULL);
		PO = Header(C.RequestList);
		for (i=0;i<C.RequestCount;i++)
		{
			fread(&P.DemandRecord,sizeof(Demand),1,fp); //read it
			Insert(P,C.RequestList,PO,EDemand);         //add to list
		}
	}

	(*ClientCount)++;
	ClientsArray = (Client*)realloc(ClientsArray,sizeof(Client)*(*ClientCount));
	ClientsArray[(*ClientCount)-1] = C;


}

fclose(fp);
return ClientsArray;
}
//Function receive the clients array and write them to file.
void WriteClientsToFile(Client *ClientsArray,int *ClientCount)
{
FILE *fp;
int i;
Position PO;
DemandProperty P;

fp = fopen(ClientsFile,"wb+");
if (fp==NULL)
{
 printf("Error Open File...");
 exit(1);
}

for (i=0;i<*ClientCount;i++)
{
	fwrite(&ClientsArray[i],sizeof(Client),1,fp);
	if (ClientsArray[i].RequestCount>0)
		{
			PO = First(ClientsArray[i].RequestList);
			while (PO!=NULL)
			{
				P=Retrieve(PO);
				fwrite(&(P.DemandRecord),sizeof(Demand),1,fp);		
				PO = Advance(PO);
			}
		}

}
fclose(fp);

}
//Function that input "Integer" value, and update it to field by pointer
int Client_Insert_Integer(int *i,int maxdigits,char *Header)
{
char *res;

res = readvalue(Header,NUM_S,0,maxdigits,NULL);
if (!res)
{
	*i=0;
	return 0;
}

*i = atoi(res);
free(res);
return 1;
}
//Function that input "Byte" value, and update it to field by pointer
int Client_Insert_Byte(byte *i,int maxdigits,char *Header)
{
char *res;

res = readvalue(Header,NUM_S,0,maxdigits,NULL);
if (!res)
{
	*i=0;
	return 0;
}

*i = (byte)atoi(res);
free(res);
return 1;

}
//Shows horizontal menu, user select value from arr array. byte value enters to b.
int Client_Insert_Between(byte *b,const char *arr[],int size,char *Header)
{
	*b = menu_hor(arr,size,0,Header,-1);
	if (*b==255) //escape was pressed
	{
		*b = 0;
		return 0;
	}
	return 1;
}
//Function that input "String" value, and update it to field by pointer
int Client_Insert_String(char *c,char *Header,int maxsize,char *range)
{
char *res;

res = readvalue(Header,range,0,maxsize,NULL);

if (!res)
	return 0;
else
{
	strcpy(c,res);
	free(res);
	return 1;
} 

}
//Function that read demand fields from user, and return it by allocated pointer.
DemandProperty * ReadDemandFromUser()
{
	DemandProperty *D;
	D = (DemandProperty*)malloc(sizeof(DemandProperty)); 

	strcpy(D->DemandRecord.DemandCity,"");

		if ((!Client_Insert_Integer(&(D->DemandRecord.DemandPrice),9,"Enter Price: "))
			||
			(!Client_Insert_Byte(&(D->DemandRecord.DemandRooms),2,"Enter Rooms: "))
		    ||
			(!Client_Insert_Between(&(D->DemandRecord.DemandKind),DPKindStrings,DPKindLength,"Select Kind:"))
			||
			(!Client_Insert_Between(&(D->DemandRecord.DemandType),DPDemandTypeStrings,ActiveStringsLength,"Select Type:"))
			||
			(!Client_Insert_String(D->DemandRecord.DemandCity,"Enter City: ",20,TEXT_S)))		
		{
			free(D);
			return NULL;
		}
    	
return D;
}
//Main add new client function, call to ReadClientFromUser Main input.
void Add_New_Client(Client **ClientsArray,int *ClientCount,VoidCallBack CB)
{
   if (ReadClientFromUser(ClientsArray,ClientCount))
	   ConfirmationMessage("User Added Successfuly.");
   else
	   ConfirmationMessage("User Aborted.");
CB();
}
//Function input new client from user including his demasnds if exist.
int ReadClientFromUser(Client **ClientsArray,int *ClientCount)
{
	char buf[50];
	Client C;
	DemandProperty *P;
	Position PO;
    int i=0;

	strcpy(C.ID,"");
	strcpy(C.Name,"");
	strcpy(C.Family,"");
		
	if (!Client_Insert_ID(&C,NULL)) return 0;
	
	if (!Client_Insert_String(C.Name,"Enter Client Name: ",20,TEXT_S))
		return 0;

	if (!Client_Insert_String(C.Family,"Enter Client Family: ",20,TEXT_S))
		return 0;
	
	if (!Client_Insert_String(C.City,"Enter Client City: ",20,TEXT_S))
		return 0;

	if (!Client_Insert_String(C.Street,"Enter Client Street: ",20,TEXT_S))
		return 0;

	if (!Client_Insert_String(C.Phone,"Enter Client Phone: ",20,NUM_S))
		return 0;

	if (!Client_Insert_Between(&C.Active,ActiveStrings,ActiveStringsLength,"Select Client Activation:"))
		return 0;

	if (!Client_Insert_Between(&C.Gender,GenderStrings,ActiveStringsLength,"Select Client Gender:"))
		return 0;
	
	strcpy(buf,"Add Property To Client [ ");
	strcat(buf,C.Name);
	strcat(buf," ] ?");

	C.RequestCount=0;
	while (AskYesNoQuestion(buf))
	{
		// first time = create the list
		if (C.RequestCount==0)
			C.RequestList = MakeEmpty(NULL);
		
		PO = Header(C.RequestList);

		P = ReadDemandFromUser(); //read demand

		if (P==NULL)
		{
			DeleteList(C.RequestList);
			return 0;
		}

		C.RequestCount++;
		Insert(*P,C.RequestList,PO,EDemand);
	}

	 (*ClientCount)++;
	 (*ClientsArray) = (Client*)realloc(*(ClientsArray),sizeof(Client)*(*ClientCount));
	 (*ClientsArray)[(*ClientCount)-1] = C;
	 //realocate new space, and update the client.

	return 1;
}
// Update demand kind field
void Client_Update_Demands_Kind(Client *ClientsArray,int DemandIndex,int cid)
{
	Position PO;
	DemandProperty *P;
	PO = AdvanceEx(First(ClientsArray[cid].RequestList),DemandIndex);
	P = RetrieveAdr(PO);
	Client_Insert_Between(&(P->DemandRecord.DemandKind) ,DPKindStrings,DPKindLength,"Select Kind:");
}
// Update demand type field
void Client_Update_Demands_Type(Client *ClientsArray,int DemandIndex,int cid)
{
	Position PO;
	DemandProperty *P;
	PO = AdvanceEx(First(ClientsArray[cid].RequestList),DemandIndex);
	P = RetrieveAdr(PO);
	Client_Insert_Between(&(P->DemandRecord.DemandType) ,DPDemandTypeStrings,ActiveStringsLength,"Select Type:");
} 
// Update demand price field
void Client_Update_Demands_Price(Client *ClientsArray,int DemandIndex,int cid)
{
	Position PO;
	DemandProperty *P;
	PO = AdvanceEx(First(ClientsArray[cid].RequestList),DemandIndex);
	P = RetrieveAdr(PO);
	Client_Insert_Integer(&(P->DemandRecord.DemandPrice),9,"Enter Price: ");
}
//Update demand city field
void Client_Update_Demands_City(Client *ClientsArray,int DemandIndex,int cid)
{
	Position PO;
	DemandProperty *P;
	PO = AdvanceEx(First(ClientsArray[cid].RequestList),DemandIndex);
	P = RetrieveAdr(PO);
	Client_Insert_String(P->DemandRecord.DemandCity,"Enter City: ",20,TEXT_S);
}
//Update demand rooms count field.
void Client_Update_Demands_Rooms(Client *ClientsArray,int DemandIndex,int cid)
{
	Position PO;
	DemandProperty *P;
	PO = AdvanceEx(First(ClientsArray[cid].RequestList),DemandIndex);
	P = RetrieveAdr(PO);
	Client_Insert_Byte(&(P->DemandRecord.DemandRooms),2,"Enter Rooms: ");
}
// Search main page function.select the search kind and perform(Qsort,Bsearch)
void SearchClients(Client **ClientsArray,int *ClientCount,VoidCallBack CB)
{
int i;	
Client_Search_Type searchid;
Client *tmparray,Ctemp,*ret;
char question[50];
CompareFuncType CompareFunc;

if (*ClientCount==0)
	{	
		ConfirmationMessage("There are no clients in the system.");
		CB();
		return;
	}

searchid = menu(SearchClientStrings,SearchClientLength,0,"Search Type",12);

if (searchid==-1) {CB();return;}

switch (searchid)
{
case Search_By_ID:{
		strcpy(question,"Enter ID To Search:");
		CompareFunc = Client_Sort_ID;
	   }
	   break;
case Search_By_Name:{
		strcpy(question,"Enter Name To Search:");
		CompareFunc = Client_Sort_Name;	   
	   }
	   break;
case Search_By_Phone:{
	   	strcpy(question,"Enter Phone To Search:");
		CompareFunc = Client_Sort_Phone;	   
	   }
	   break;
}

tmparray = (Client*)malloc(sizeof(Client)*(*ClientCount));
for(i=0;i<*ClientCount;i++)
	memcpy(&tmparray[i],&(*ClientsArray)[i],sizeof(Client));

qsort(tmparray,*ClientCount,sizeof(Client),CompareFunc);

memcpy(&Ctemp,&tmparray[0],sizeof(Client));

switch (searchid)
{
case Search_By_ID:
		{
		if(!Client_Insert_ID(&Ctemp,NULL)) return;
	    }
	   break;
case Search_By_Name:{
		if (!Client_Insert_String(Ctemp.Name,"Enter Client Name: ",20,TEXT_S))
			return;
		
	   }
	   break;
case Search_By_Phone:{
		if (!Client_Insert_String(Ctemp.Phone,"Enter Client Phone: ",20,NUM_S))
			return;
	   }
	   break;
}
//search the client using bsearch.
ret = (Client *)bsearch(&Ctemp,tmparray,*ClientCount,sizeof(Client),CompareFunc);

if (ret!=NULL && ret->Active==0) // if found , and is active
{
	ShowClient(ClientsArray,ClientCount,ret, -1); // shows it.
}
else
	ConfirmationMessage("Client Not Found.");

free(tmparray); //free
CB();

}
//Compare ID function
int Client_Sort_ID(const void *arg1, const void *arg2)
{
	return strcmp((*(Client *)arg1).ID,(*(Client *)arg2).ID);
}
//Compare Name function
int Client_Sort_Name(const void *arg1, const void *arg2)
{
	return strcmp((*(Client *)arg1).Name,(*(Client *)arg2).Name);
}
// Compare Phone function
int Client_Sort_Phone(const void *arg1, const void *arg2)
{
	return strcmp((*(Client *)arg1).Phone,(*(Client *)arg2).Phone);
}
//Input ID from user until it will be valid 9 number ID(Recursive)
int Client_Insert_ID(Client *C,char *msg)
{
char *tmp;
tmp = readvalue("Enter Client ID:",NUM_S,0,9,msg);
if (tmp==NULL)
	return 0;
else
	if ((int)strlen(tmp)<9)
	{
	free(tmp);
	return Client_Insert_ID(C,"ID not valid (9 digits required)");
	}
	else
	{
		strcpy(C->ID,tmp);
		free(tmp);
		return 1;
	}
}
//Select client from menu, and asks to delete it.
void DeleteClients(Client **ClientsArray,int *ClientCount,VoidCallBack CB)
{
int cid;

if (*ClientCount==0)
	{	
		ConfirmationMessage("There are no clients in the system.");
		return;
	}

cid = SelectClientFromList(*ClientsArray,ClientCount);
if (cid == -1) return;

Start_Delete_Client(ClientsArray,ClientCount,cid);

CB();

}
// Shows Submenu for edir demands it the ShowClient page.
void Start_Edit_Demands(Client *ClientsArray,int *ClientCount,int cid)
{
int editid;
editid = menu(DemandEditStrings,ActiveStringsLength,0,"Edit",12);
if (editid==-1)
	return;

switch (editid)
{
case 0:Add_Demand_To_Client(ClientsArray,ClientCount,cid);break;
case 1:Delete_Demand_From_Client(ClientsArray,ClientCount,cid);break;
}

}
//Function receive client id, input demand fields and adds new demand to the user.
void Add_Demand_To_Client(Client *ClientsArray,int *ClientCount,int cid)
{
DemandProperty *D;
D = ReadDemandFromUser();
if (D==NULL)
{
	free(D);
	return;
}

if (ClientsArray[cid].RequestCount==0)
	ClientsArray[cid].RequestList = MakeEmpty(NULL);

Insert(*D,ClientsArray[cid].RequestList,Header(ClientsArray[cid].RequestList),EDemand);
ClientsArray[cid].RequestCount++;

}
//Function shows demands of specific client, and then delete this demand.
void Delete_Demand_From_Client(Client *ClientsArray,int *ClientCount,int cid)
{
int demid;

demid = Select_Client_Request(ClientsArray[cid]);

if (demid==-1)
	return;

DeleteInd(demid,ClientsArray[cid].RequestList);
ClientsArray[cid].RequestCount--;

if (ClientsArray[cid].RequestCount==0)
	DeleteList(ClientsArray[cid].RequestList);

}
//Function deletes the client.first all his demands, and then the client.
void Start_Delete_Client(Client **ClientsArray,int *ClientCount,int cid)
{
int i;
char BUF[100];

strcat(strcat(strcpy(BUF,"Are you sure you want delete ["),(*ClientsArray)[cid].Name),"] ?");

if (!AskYesNoQuestion(BUF))
	return;

if ((*ClientsArray)[cid].RequestCount>0)
	DeleteList((*ClientsArray)[cid].RequestList);

for(i=cid;i<*ClientCount-1;i++)
	memcpy(&(*ClientsArray)[i],&(*ClientsArray)[i+1],sizeof(Client));

(*ClientCount)--;
*(ClientsArray) = (Client*)realloc(*ClientsArray,sizeof(Client)*(*ClientCount));

ConfirmationMessage("Client Deleted.");

}
//find client C by memory compare, in the array of clients.
int FindClientID(Client *ClientsArray,int *ClientCount,Client *C)
{
int i,ret=-1;
for(i=0;i<*ClientCount;i++)
	if (memcmp((Client*)C,(Client*)(&ClientsArray[i]),sizeof(Client))==0)
	{
		ret = i;
		break;
	}

return ret;
}
//print the Submenu options.
void ClientsOptions()
{
	puttext("Client Options : (U)pdate, (E)rase, (D)emands.",5,23,0x0f,0,0);
	puttext("U",5+18,23,0x0c,0,0);
	puttext("E",5+28,23,0x0c,0,0);
	puttext("D",5+37,23,0x0c,0,0);
}
//Main reports menu.user select the report type, and then perform it.
void Show_Reports(Client *ClientsArray,int *ClientCount,List PropertiesList,int *PropertiesCount)
{
int repid;

repid = menu(ReportsStrings,ReportsStringsLength,0,"Select Report",12);

if (repid==-1)
	return;

switch (repid)
{
case 0 :   Show_Reports_Sort_Demands(ClientsArray,ClientCount); break;
case 1:    Show_Reports_Sort_Clients(ClientsArray,ClientCount,repid); break;
case 2:    Show_Reports_Sort_Clients(ClientsArray,ClientCount,repid); break;
case 3:    Show_Reports_List_Demands_By_Client(ClientsArray,ClientCount);break;
case 4:    Show_Reports_Properties_Text_File(PropertiesList,PropertiesCount);break;
case 5:    Show_Reports_Properties_By_Name_Text_File(PropertiesList,PropertiesCount);break;
}
}
//Print recursively all the demands of L list vertically. 
void Print_Demands_In_Recursion(Position L,int index)
{
	DemandProperty P;

	if (Advance(L))
		Print_Demands_In_Recursion(Advance(L),index-1);
	
	P = Retrieve(L);
	gotoxy(5,index+5);
	printf("%d: %s, %d$, %s, %s, %d rooms. ",index,P.DemandRecord.DemandCity ,
	P.DemandRecord.DemandPrice,DPKindStrings[P.DemandRecord.DemandKind],
	DPDemandTypeStrings[P.DemandRecord.DemandType],P.DemandRecord.DemandRooms);

}
// Function print the demands of specific client.
void Show_Reports_List_Demands_By_Client(Client *ClientsArray,int *ClientCount)
{
int clientid;

if (*ClientCount==0)
{
	ConfirmationMessage("There are no users in the system !");
	return;
}

clientid = SelectClientFromList(ClientsArray,ClientCount);
if(clientid==-1)
	return;

showoutputimage(0);

puttext("Demands",40,2,0x0c,1,0);
fillascii(3,3,75,3,'-',0x0c);

settextcolor(0x0d);
gotoxy(5,5);
Print_Demands_In_Recursion(First(ClientsArray[clientid].RequestList),ClientsArray[clientid].RequestCount);

getch();
}
//Function Qsorts the client array (by ID or Name)
void Show_Reports_Sort_Clients(Client *ClientsArray,int *ClientCount,int repid)
{
CompareFuncType F;

if (*ClientCount==0)
{
	ConfirmationMessage("There are no users in the system !");
	return;
}

switch (repid)
{
case 1:F = Client_Sort_ID ;  break;
case 2:F = Client_Sort_Name; break;
}

qsort(ClientsArray,*ClientCount,sizeof(Client),F);

ConfirmationMessage("Clients Sorted.");

}

//Function sort demands of specific client.
void Show_Reports_Sort_Demands(Client *ClientsArray,int *ClientCount)
{
int clientid,fieldid,i,NumOfDemands;
Demand *Demands;
Position PO;
Demand ClientDemand;
DemandProperty *D;
Client *C;
BubbleFuncType B;

if (*ClientCount==0)
{
	ConfirmationMessage("There are no users in the system !");
	return;
}

clientid = SelectClientFromList(ClientsArray,ClientCount);

if (clientid==-1)
	return;

C = &(ClientsArray[clientid]);
if (C->RequestCount==0)
	{
		ConfirmationMessage("Client Don't Have Any Demand...");
		return;
	}

fieldid = menu(SortClientDemandFields,SortClientDemandFieldsLength,0,"Sort By",12);
if (fieldid==-1)
	return;

switch (fieldid)
{
case 0:B = Sort_Demand_By_Price; break;
case 1:B = Sort_Demand_By_City ; break;
case 2:B = Sort_Demand_By_Type ; break;
}

Demands = (Demand*)malloc(sizeof(Demand) * C->RequestCount);

PO = First(C->RequestList);
//moving from list to array
for(i=0;i<C->RequestCount;i++)
{
	ClientDemand = Retrieve(PO).DemandRecord;
	memcpy(&Demands[i],&ClientDemand,sizeof(Demand));
	PO = Advance(PO);
}

NumOfDemands = C->RequestCount;

bubble_sort(Demands,C->RequestCount,B);// bubble sorting

DeleteList(C->RequestList); //delete current list
C->RequestCount = 0; //reset count

C->RequestList = MakeEmpty(NULL); //creating again
PO = Header(C->RequestList);


for(i=0;i<NumOfDemands;i++) //insert sorted items again to the list
{
	D = (DemandProperty*)malloc(sizeof(DemandProperty));
	memcpy(&(D->DemandRecord),&Demands[i],sizeof(Demand));

	Insert(*D,C->RequestList,PO,EDemand);
	C->RequestCount++;	
}

ConfirmationMessage("Sort Updated");

}
//Bubble sort function by external method compare - B.
void bubble_sort(Demand *Arr, int size,BubbleFuncType B)
{
int pass=1, i;
Demand temp;
char exchanges = 'y';
	while (pass< size && exchanges == 'y')
	{ 
		exchanges = 'n';
		for (i=0; i < size - pass; i++)
		{  			
			if (B(Arr[i],Arr[i+1]))
			{   
				memcpy(&temp,&Arr[i],sizeof(Demand));
				memcpy(&Arr[i],&Arr[i+1],sizeof(Demand));
				memcpy(&Arr[i+1],&temp,sizeof(Demand));
				
				exchanges='y';
			} 
		} 
		pass=pass+1;
	} 
}
//Bubble sort compare function
int Sort_Demand_By_Price(const Demand d1,const Demand d2)
{
return (d1.DemandPrice < d2.DemandPrice);
}
//Bubble sort compare function
int Sort_Demand_By_City(const Demand d1,const Demand d2)
{
	return (strcmp(d1.DemandCity,d2.DemandCity)>0)?(0):(1);
}
//Bubble sort compare function
int Sort_Demand_By_Type(const Demand d1,const Demand d2)
{
	return (strcmp(DPDemandTypeStrings[d1.DemandType],DPDemandTypeStrings[d2.DemandType])>0)?(0):(1);
}
//Before exit of the program, clear all client demands, and all info.
void FreeClientAllocationsBeforeExit(Client *ClientsArray,int *ClientCount)
{
int i;
for(i=0;i<(*ClientCount);i++)
{
	if (ClientsArray[i].RequestCount>0)
		DeleteList(ClientsArray[i].RequestList);
}
if (*ClientCount>0)
	free(ClientsArray);

}
//fill stirng BUF with info's from the Demand record
void FillDemandInfo(DemandProperty *D,char **BUF)
{
	sprintf(*BUF,"%s, %s, %s, %d, %d$.",D->DemandRecord.DemandCity,
	DPKindStrings[D->DemandRecord.DemandKind],
	DPDemandTypeStrings[D->DemandRecord.DemandType],
	D->DemandRecord.DemandRooms,D->DemandRecord.DemandPrice);
}
